﻿using Domain.IRepositorys;
using Domain.Model;
using Domain.Services;
using Domain.Types;
using DTO;
using Infrastructure.Error;
using Infrastructure.UniOfWorkBase;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using OtherLib.AliPay;
using OtherLib.TenXun;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Utility;

namespace Application.App
{
    public class PayApplication
    {
        public PayService payService { get; set; }
        public IEFUnitOfWork efUnitOfWork { get; set; }
        public ICapitalFlowRepository capitalFlowRepository { get; set; }
        public IWxMiniRepository wxMiniRepository { get; set; }
        public IPayCallBackLogRepository payCallBackLogRepository { get; set; }

        public ILogger<PayApplication> _logger { get; set; }

        public string CreatePayInfo(int uid, PayMoneyInput payMoneyInput)
        {
            var serialNo = IDGeneratorUtil.GetId();

            CapitalFlowAggregate capitalFlowAggregate = new CapitalFlowAggregate();

            capitalFlowAggregate.SerialNO = serialNo.ToString();
            capitalFlowAggregate.FlowType = payMoneyInput.PayTypeEnum;
            capitalFlowAggregate.BizType = payMoneyInput.CapitalFlowBizType;
            capitalFlowAggregate.BizDesc = payMoneyInput.CapitalFlowBizType.ToString();
            capitalFlowAggregate.BizParams = payMoneyInput.Data;
            capitalFlowAggregate.Institution = capitalFlowAggregate.FlowType.ToString();
            capitalFlowAggregate.Status = CapitalFlowStatus.待支付;
            capitalFlowAggregate.StatusName = capitalFlowAggregate.Status.ToString();
            capitalFlowAggregate.UserID = uid;
            capitalFlowAggregate.PayMoney = payMoneyInput.PayMoney;

            capitalFlowRepository.Insert(capitalFlowAggregate);

            efUnitOfWork.Commit();

            switch (payMoneyInput.PayTypeEnum)
            {
                default:
                case PayChannelEnum.支付宝:
                    var r = AliPayUtil.AliPlay(((double)(payMoneyInput.PayMoney)/100).ToString(), capitalFlowAggregate.SerialNO, capitalFlowAggregate.BizDesc, uid.ToString());
                    return r;
                case PayChannelEnum.微信App:
                    {
                        var util = TenXunPayUtil.GetUtilByName("App");
                        var r1 = util.AppPay(uid.ToString(), capitalFlowAggregate.SerialNO, payMoneyInput.PayMoney).GetAwaiter().GetResult();
                        return r1.Item2;
                    }
                case PayChannelEnum.微信小程序:
                    {
                        var util = TenXunPayUtil.GetUtilByName("Mini");
                        var wx = wxMiniRepository.Entities.FirstOrDefault(i => i.UserID == uid);
                        var r1 = util.JsApiPay(uid.ToString(), capitalFlowAggregate.SerialNO, payMoneyInput.PayMoney, wx.WxOpenID).GetAwaiter().GetResult();
                        return r1.Item2;
                    }
            }

        }

        public bool WxPayNotify(Stream body, string fromName)
        {
            try
            {
                var util = TenXunPayUtil.GetUtilByName(fromName);
                //获取微信回调请求参数
                var data = util.WeChatNotify(body).GetAwaiter().GetResult();
                Console.WriteLine(JsonConvert.SerializeObject(data));
                //判断回调的有效性，是否成功
                if (data.IsVerify)
                {
                    Console.WriteLine(JsonConvert.SerializeObject(data));

                    var returnCode = (string)data.Content.GetValue("return_code");
                    var resultCode = (string)data.Content.GetValue("return_msg");

                    var payTime = DateTime.ParseExact(data.PayTime, "yyyyMMddHHmmss", System.Globalization.CultureInfo.CurrentCulture);

                    //记录日志
                    PayCallBackLogAggregate payCallBackLogAggregate = new PayCallBackLogAggregate();

                    payCallBackLogAggregate.InstitutionCT = payTime;
                    payCallBackLogAggregate.InstitutionLog = JsonConvert.SerializeObject(data);
                    payCallBackLogAggregate.InstitutionNO = data.PayNo;
                    payCallBackLogAggregate.SerialNO = data.TradeIds;
                    payCallBackLogAggregate.FlowType = PayChannelEnum.支付宝;
                    payCallBackLogAggregate.InstitutionTradeSuccess = returnCode == "SUCCESS" && resultCode == "OK";

                    payCallBackLogRepository.Insert(payCallBackLogAggregate);
                    efUnitOfWork.Commit();
                    efUnitOfWork.Reset();


                    var c = capitalFlowRepository.Entities.FirstOrDefault(i => i.SerialNO == data.TradeIds);

                    if (c == null) return true;
                    if (c.IsHandle) throw new BizException("该支付回调已经被处理!");

                    c.InstitutionCT = payTime;
                    c.InstitutionLog = payCallBackLogAggregate.InstitutionLog;
                    c.InstitutionNO = data.PayNo;
                    c.InstitutionTradeSuccess = payCallBackLogAggregate.InstitutionTradeSuccess;
                    c.Status = payCallBackLogAggregate.InstitutionTradeSuccess ? CapitalFlowStatus.成功 : CapitalFlowStatus.取消支付;
                    c.StatusName = c.Status.ToString();
                    efUnitOfWork.Commit();
                    efUnitOfWork.Reset();

                    bool r = false;
                    try
                    {
                        r = PolicyUtil.WaitAndRetry(new[] { 1, 2, 3 }, () =>
                        {
                            return payService.PayHandle(c);
                        });
                    }
                    catch (Exception ex)//一直锁定，需要检查????
                    {
                        efUnitOfWork.Rollback();
                        _logger.LogException(ex);

                        payCallBackLogAggregate.IsHandle = false;
                        payCallBackLogAggregate.IsError = true;
                        payCallBackLogAggregate.HandleInfo = JsonConvert.SerializeObject(ex);
                        payCallBackLogRepository.Update(payCallBackLogAggregate);
                        efUnitOfWork.Commit();

                        throw ex;
                    }
                    payCallBackLogAggregate.IsHandle = true;
                    payCallBackLogAggregate.HandleInfo = c.HandleInfo;
                    payCallBackLogRepository.Update(payCallBackLogAggregate);
                    efUnitOfWork.Commit();

                    return r;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("微信支付回调->WxPayNotify，错误消息：" + ex.Message);
            }

            return false;
        }

        public bool AliPayNotify(Dictionary<string, string> package, AliPayNotifyInput aliPayNotifyInput)
        {
            _logger.LogInformation("支付宝支付回调:  " + JsonConvert.SerializeObject(package));
            //记录日志
            PayCallBackLogAggregate payCallBackLogAggregate = new PayCallBackLogAggregate();

            payCallBackLogAggregate.InstitutionCT = aliPayNotifyInput.gmt_create;
            payCallBackLogAggregate.InstitutionLog = JsonConvert.SerializeObject(package);
            payCallBackLogAggregate.InstitutionNO = aliPayNotifyInput.trade_no;
            payCallBackLogAggregate.SerialNO = aliPayNotifyInput.out_trade_no;
            payCallBackLogAggregate.FlowType = PayChannelEnum.支付宝;
            payCallBackLogAggregate.InstitutionTradeSuccess = aliPayNotifyInput.trade_status == "TRADE_SUCCESS";

            payCallBackLogRepository.Insert(payCallBackLogAggregate);
            efUnitOfWork.Commit();

            efUnitOfWork.Reset();
            
            aliPayNotifyInput.IsSafe = AliPayUtil.RSACheckV1(package);
            _logger.LogInformation("支付宝支付回调:  aliPayNotifyInput.IsSafe:" + aliPayNotifyInput.IsSafe);

            if (!aliPayNotifyInput.IsSafe) return false;

            var c = capitalFlowRepository.Entities.FirstOrDefault(i => i.SerialNO == aliPayNotifyInput.out_trade_no);

            if (c == null) return false;
            if (c.IsHandle) throw new BizException("该支付回调已经被处理!");

            c.InstitutionCT = aliPayNotifyInput.gmt_create;
            c.InstitutionLog = payCallBackLogAggregate.InstitutionLog;
            c.InstitutionNO = aliPayNotifyInput.trade_no;
            c.InstitutionTradeSuccess = payCallBackLogAggregate.InstitutionTradeSuccess;
            c.Status = payCallBackLogAggregate.InstitutionTradeSuccess ? CapitalFlowStatus.成功 : CapitalFlowStatus.取消支付;
            c.StatusName = c.Status.ToString();

            efUnitOfWork.Commit();
            efUnitOfWork.Reset();

            bool r = false;
            try
            {
                r = PolicyUtil.WaitAndRetry(new[] { 1, 2, 3 }, () =>
                {
                    return payService.PayHandle(c);
                });
            }
            catch (Exception ex)//一直锁定，需要检查????
            {
                efUnitOfWork.Rollback();
                _logger.LogException(ex);

                payCallBackLogAggregate.IsHandle = false;
                payCallBackLogAggregate.IsError = true;
                payCallBackLogAggregate.HandleInfo = JsonConvert.SerializeObject(ex);
                payCallBackLogRepository.Update(payCallBackLogAggregate);
                efUnitOfWork.Commit();

                throw ex;
            }
            payCallBackLogAggregate.IsHandle = true;
            payCallBackLogAggregate.HandleInfo = c.HandleInfo;
            payCallBackLogRepository.Update(payCallBackLogAggregate);
            efUnitOfWork.Commit();

            return r;
        }


    }
}
